package com.back.service.tool;

import com.back.excepction.BaseException;
import com.back.model.MinIOProperty;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

// https://blog.csdn.net/weixin_43224069/article/details/125675877

@Component
@Slf4j
public class MinioService {



    @Resource
    private MinioClient minioClient;

    @Resource private MinIOProperty minioProperty;

    /**
     * 上传
     */
    public String uploadFile(MultipartFile file) {
        // 获取桶名
        String bucketName = minioProperty.getBucketName();
        log.info("开始向桶 {} 上传文件", bucketName);
        //给文件生成一个唯一名称  当日日期-uuid.后缀名
        String folderName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"));
        String fileName = String.valueOf(UUID.randomUUID());
        String extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));//文件后缀名
        String objectName = folderName + "-" + fileName + extName;

        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
            // 配置参数
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName)
                    .stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            log.error("文件上传失败: " + e);
            throw new RuntimeException(e);
        }
        log.info("文件上传成功，文件名为：{}", objectName);
        String presignedUrl = getPresignedUrl(objectName);
        return presignedUrl;
    }


    /**
     * 下载
     */
    public void downloadFile(String fileName, HttpServletResponse response) {
        // 获取桶名
        String bucketName = minioProperty.getBucketName();
        if (StringUtils.isBlank(fileName)) {
            log.error("文件名为空！");
            return;
        }
        try {
            // 获取文件流
            InputStream file = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), String.valueOf(StandardCharsets.UTF_8)));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            // 获取输出流
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = file.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            file.close();
            servletOutputStream.close();
            log.info("文件{}下载成功", fileName);
        } catch (Exception e) {
            log.error("文件名: " + fileName + "下载文件时出现异常: " + e);
        }
    }

    /**
     * 删除
     */
        public void deleteFile(String fileName){
            // 获取桶名
            String bucketName = minioProperty.getBucketName();
            try {
                if (StringUtils.isBlank(fileName)) {
                    log.error("删除文件失败，文件名为空！");
                    return;
                }
                // 判断桶是否存在
                boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
                // 桶存在
                if (isExist) {
                    minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                } else { // 桶不存在
                    log.error("删除文件失败，桶{}不存在", bucketName);
                }
            } catch (Exception e) {
                log.error("删除文件时出现异常: " ,e);
                throw new BaseException("删除失败"+e.getMessage());
            }
        }

    /**
     * 获取文件预览url
     *
     * @param fileName 文件名
     * @return 文件预览url
     */
    public String getPresignedUrl(String fileName) {
        // 获取桶名
        String bucketName = minioProperty.getBucketName();
        String presignedUrl = null;
        try {
            if (StringUtils.isBlank(fileName)) {
                log.error("获取文件预览url失败，文件名为空！");
                return presignedUrl;
            }
            // 判断桶是否存在
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            // 桶存在
            if (isExist) {
                // if (minioProperty.getPreviewExpiry() != null){
                //     presignedUrl = minioClient.getPresignedObjectUrl(
                //             GetPresignedObjectUrlArgs.builder()
                //                     .method(Method.GET)
                //                     .bucket(bucketName)
                //                     .object(fileName)
                //                     .expiry(1, TimeUnit.DAYS) // 一天过期时间
                //                     .build());
                // }else {
                //     // 默认过期时间7天
                //     presignedUrl = minioClient.getPresignedObjectUrl(
                //             GetPresignedObjectUrlArgs.builder()
                //                     .method(Method.GET)
                //                     .bucket(bucketName)
                //                     .object(fileName)
                //                     .build());
                // }
                presignedUrl =minioProperty.getEndpoint()+"/"+minioProperty.getBucketName()+"/"+fileName;
                return presignedUrl;
            } else {  // 桶不存在
                log.error("获取文件预览url失败，桶{}不存在", bucketName);
            }
        } catch (Exception e) {
            log.error("获取文件预览url时出现异常: " + e.getMessage());
        }
        return presignedUrl;
    }

}
